#include "Guid.h"

#include "Containers/Hash.h"

#ifdef WIN32
   #include <combaseapi.h>
#else
    #include <uuid/uuid.h>
#endif

SGuid SGuid::NewGuid()
{

#ifdef WIN32
    SGuid Ret;
    CoCreateGuid( reinterpret_cast<GUID*>(&Ret));
    return Ret;
#else
    SGuid Ret;
    uuid_generate(reinterpret_cast<unsigned char*>(&Ret));
    return Ret;
#endif 



}

uint64_t SGuid::GetHashCode() const
{
    return WH::HashCombine(
        ((uint64_t)A<<32)+((uint64_t)B<<16)+C
        , std::hash<uint64_t>{}(D)
        );
}

bool SGuid::IsValid() const
{
    return A!=0 || B!=0  || C!=0 || D!=0;
}

CString SGuid::ToString() const
{
    char8_t String [32+4+1];
    String[8]='_';
    String[13]='_';
    String[18]='_';
    String[23]='_';
    String[36]='\0';

    static char8_t HexChars [16] ={U'0',U'1',U'2',U'3',U'4',U'5',U'6',U'7',U'8',U'9',U'A',U'B',U'C',U'D',U'E',U'F'};

    for(int index=0;index<8;index++)
    {
        String[index] =HexChars[(A>> ((7-index)*4) ) & 0b1111];
    }

    for(int index=9;index<13;index++)
    {
        String[index] = HexChars[(B>> ((3-index+9)*4) )& 0b1111];
    }

    for(int index=14;index<18;index++)
    {
        String[index] = HexChars[(C>> ((3-index+14)*4) )& 0b1111];
    }

    for(int index=19;index<23;index++)
    {
        String[index] = HexChars[(D>> ((15-index+19)*4) )& 0b1111];
    }

    for(int index=24;index<36;index++)
    {
        String[index] = HexChars[(D>> ((11-index+24)*4) )& 0b1111];
    }

    return CString(String);
}


void SGuid::Fill(const CString& InString)
{   
    A=0;
    B=0;
    C=0;
    D=0;

    auto CStr=InString.ToUtf8();

    static const uint64_t HexValues[256] = {
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
    0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    };

    for(int index=0;index<8;index++)
    {
        A+= HexValues[CStr[index]] << (4*(7-index));
    }

    for(int index=9;index<13;index++)
    {
        B+=HexValues[CStr[index]] << (4*( 12-index));
    }

    for(int index=14;index<18;index++)
    {
        C+=HexValues[CStr[index]] << (4*( 17-index));
    }

    for(int index=19;index<23;index++)
    {
        D+=HexValues[CStr[index]] << (4*(16-4 +22-index));
    }

    for(int index=24;index<36;index++)
    {
        D+=HexValues[CStr[index]] << (4*(35-index));
    }

}

SGuid SGuid::FromString(const CString &InString)
{
    SGuid Ret;
    Ret.Fill(InString);
    return Ret;
}
